#pragma once

#include <iostream>
#include <unordered_map>
#include <memory>
#include <sys/epoll.h>
#include <unistd.h>

#include "Connection.hpp"
#include "Epoller.hpp"
#include "Log.hpp"
#include "Comm.hpp"

// Reactor的作用:
// 1、为每个文件描述符设置输入输出缓冲区
// 2、内部管理epoll、每个文件描述符构成的类
class Reactor
{
public:
    Reactor(std::string proccessname, sem_t *sem) : _proccessname(proccessname), _running(false), _sem(sem)
    {
    }
    void DelConnection(int sockfd)
    {
        if (!ConnectionIsExists(sockfd))
            return;
        _ep.DelEvent(sockfd);
        _conn[sockfd]->Close();
        delete _conn[sockfd];
        _conn.erase(sockfd);
    }
    void AddConnection(int fd, uint32_t events, func_t recver, func_t sender, func_t excepter)
    {
        // 添加epoll、键值对
        Connection *con = new Connection(fd);
        con->SetSelf(this);
        con->SetEvent(events);
        // 对于添加的新关系文件描述符，需要指名其回调方法（区分listen和普通套接字）
        con->Register(recver, sender, excepter);

        _ep.AddEvent(fd, events);
        _conn[fd] = con;
        LOG(DEBUG, "Add a new connection, sockfd is %d", fd);
    }
    bool ConnectionIsExists(int sockfd)
    {
        auto iter = _conn.find(sockfd);
        return iter != _conn.end();
    }
    void EnableReadWrite(int sockfd, bool readable, bool writeable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
        if (ConnectionIsExists(sockfd))
        {
            _conn[sockfd]->SetEvent(events);
            _ep.ModEvent(sockfd, events);
        }
    }
    void LoopOnce(int timeout)
    {
        int n = _ep.WaitEvent(_revs, Gval::gnum, timeout);

        // if (n > 0)
        //     LOG(DEBUG, "%d event are ready:%d", n, getpid());
        for (int i = 0; i < n; ++i)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            // 将标准错误、退出信号都视为标准输入输出
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLIN)
            {
                if (ConnectionIsExists(sockfd) && _conn[sockfd]->recver() != nullptr)
                {
                    _conn[sockfd]->recver()(_conn[sockfd]);
                }
            }
            if (revents & EPOLLOUT)
            {
                if (ConnectionIsExists(sockfd) && (_conn[sockfd]->sender() != nullptr))
                {
                    _conn[sockfd]->sender()(_conn[sockfd]);
                }
            }
        }
    }
    std::string Name()
    {
        return _proccessname;
    }
    // 派发事件
    void Dispatcher()
    {
        _running = true;
        int timeout = 0;
        while (_running)
        {
            LoopOnce(timeout);
            // std::cout << _proccessname << "-timeout..." << std::endl;
        }
        _running = false;
    }
    ~Reactor() {}

private:
    // 将文件描述符和对应的管理Connection关联
    std::unordered_map<int, Connection *> _conn;
    // 底层的epoll结构
    Epoller _ep;
    // epoll返回的就绪事件
    struct epoll_event _revs[Gval::gnum];
    bool _running;
    std::string _proccessname;
    sem_t *_sem;
};